/*静态配置库操作
Created on 2020年05月10日
@author: zxyong 13738196011
 */

package com.zxy.db_Self;

import com.zxy.common.Com_Fun;
import com.zxy.common.Com_Para;

import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Date;
import java.util.Enumeration;
import java.util.Vector;

public class ConnectionPool_Self
{
	public String							jdbcDriver				= "";
	private String							dbUrl					= "";
	private String							dbUsername				= "";
	private String							dbPassword				= "";
	private int								initialConnections		= 5;
	private int								incrementalConnections	= Com_Para.incrementalConnections;
	private int								maxConnections			= Com_Para.maxConnections;
	private Vector<PooledConnection_Self>	connections				= null;

	public ConnectionPool_Self(String jdbcDriver,String dbUrl,String dbUsername,String dbPassword)
	{
		if(jdbcDriver.equals("org.sqlite.JDBC"))
			this.initialConnections = 2;
		this.jdbcDriver = jdbcDriver;
		this.dbUrl = dbUrl;
		this.dbUsername = dbUsername;
		this.dbPassword = dbPassword;
		try
		{
			createPool();
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
	}

	public int getInitialConnections()
	{
		return this.initialConnections;
	}

	public void setInitialConnections(int initialConnections)
	{
		this.initialConnections = initialConnections;
	}

	public int getIncrementalConnections()
	{
		return this.incrementalConnections;
	}

	public void setIncrementalConnections(int incrementalConnections)
	{
		this.incrementalConnections = incrementalConnections;
	}

	public int getMaxConnections()
	{
		return this.maxConnections;
	}

	public void setMaxConnections(int maxConnections)
	{
		this.maxConnections = maxConnections;
	}

	public synchronized void createPool() throws Exception
	{
		if(this.connections != null)
		{
			return;
		}
		Driver driver = (Driver)Class.forName(this.jdbcDriver).newInstance();
		DriverManager.registerDriver(driver);
		this.connections = new Vector<PooledConnection_Self>();
		createConnections(this.initialConnections);
		System.out.println("myself db create pool");
	}

	private void createConnections(int numConnections) throws SQLException
	{
		for(int x = 0;x < numConnections;x++)
		{
			if((this.maxConnections > 0) && (this.connections.size() >= this.maxConnections))
			{
				System.out.println("myself db 连接数己经达到最大");
				break;
			}

			try
			{
				this.connections.addElement(new PooledConnection_Self(newConnection()));
			}
			catch(SQLException e)
			{
				System.out.println("myself db  创建数据库连接失败！ " + e.getMessage());
				throw new SQLException();
			}
		}
	}

	private Connection newConnection() throws SQLException
	{
		Connection conn = DriverManager.getConnection(this.dbUrl,this.dbUsername,this.dbPassword);
		if(this.connections.size() == 0)
		{
			DatabaseMetaData metaData = conn.getMetaData();
			int driverMaxConnections = metaData.getMaxConnections();

			if((driverMaxConnections > 0) && (this.maxConnections > driverMaxConnections))
			{
				this.maxConnections = driverMaxConnections;
			}
		}
		return conn;
	}

	public synchronized PooledConnection_Self getConnection() throws SQLException
	{
		if(this.connections == null)
		{
			return null;
		}
		PooledConnection_Self conn = getFreeConnection();
		while(conn == null)
		{
			wait(250);
			conn = getFreeConnection();
		}
		return conn;
	}

	private PooledConnection_Self getFreeConnection() throws SQLException
	{
		PooledConnection_Self conn = findFreeConnection();
		if(conn == null)
		{
			createConnections(this.incrementalConnections);
			conn = findFreeConnection();
			if(conn == null)
			{
				return null;
			}
		}
		return conn;
	}

	private PooledConnection_Self findFreeConnection() throws SQLException
	{
		for(int i = 0;i < this.connections.size();i++)
		{
			PooledConnection_Self pc = (PooledConnection_Self)this.connections.elementAt(i);
			if(!pc.isBusy())
			{
				Connection conn = pc.getConnection();
				pc.setBusy(true);

				if(!isValid(conn))
				{
					try
					{
						conn = newConnection();
						pc.setConnection(conn);
					}
					catch(SQLException e)
					{
						e.printStackTrace();
						this.connections.remove(i--);
						System.out.println("删除mySelf连接,当前总连接数:" + this.connections.size());
						continue;
					}
				}
				return pc;
			}
		}
		return null;
	}

	private boolean isValid(Connection conn)
	{
		try
		{
			if(this.jdbcDriver.equals("org.sqlite.JDBC"))
				return !conn.isClosed();
			else if(this.jdbcDriver.indexOf("oracle") != -1)
				return conn.isValid(1000);
			else return !conn.isClosed();
		}
		catch(SQLException e)
		{
			e.printStackTrace();
			return false;
		}
		catch(Exception es)
		{
			es.printStackTrace();
		}
		return false;
	}

	public void returnConnection(Connection conn)
	{
		if(this.connections == null)
		{
			System.out.println("myself db  连接池不存在，无法返回此连接到连接池中 !");
			return;
		}

		PooledConnection_Self pConn = null;
		Enumeration<PooledConnection_Self> enumerate = this.connections.elements();

		while(enumerate.hasMoreElements())
		{
			pConn = (PooledConnection_Self)enumerate.nextElement();

			if(conn == pConn.getConnection())
			{
				pConn.setBusy(false);
				break;
			}
		}
	}

	public synchronized void refreshConnections() throws SQLException
	{
		if(this.connections == null)
		{
			System.out.println("myself db  连接池不存在，无法刷新 !");
			return;
		}

		PooledConnection_Self pConn = null;
		Enumeration<PooledConnection_Self> enumerate = this.connections.elements();
		while(enumerate.hasMoreElements())
		{
			pConn = (PooledConnection_Self)enumerate.nextElement();

			if(pConn.isBusy())
			{
				wait(5000);
			}

			closeConnection(pConn.getConnection());
			pConn.setConnection(newConnection());
			pConn.setBusy(false);
		}
	}

	// 超时连接。
	public synchronized void closeConnectionPoolTimeOut() throws SQLException
	{
		PooledConnection_Self pConn = null;
		if(connections != null)
		{
			int iIndex = 0;
			Enumeration<PooledConnection_Self> enumerate = connections.elements();
			while(enumerate.hasMoreElements())
			{
				pConn = (PooledConnection_Self)enumerate.nextElement();
				if(pConn.updtime + 180000 < new Date().getTime())// 300000
				{
					isValid(pConn.getConnection());
					if(iIndex < initialConnections)
					{
						try
						{
							pConn.executeQuery(new StringBuilder("select 1"));
						}
						catch(Exception e)
						{
							e.printStackTrace();
						}
						finally
						{
							pConn.returnConnection();
						}
					}
					// 超过initialConnections个连接关闭
					else
					{
						closeConnection(pConn.getConnection());
						connections.removeElement(pConn);
						System.out.println("删除mySelf连接,当前总连接数:" + this.connections.size());
					}
				}
				iIndex++;
			}
		}
	}

	public synchronized void closeConnectionPool() throws SQLException
	{
		if(this.connections == null)
		{
			System.out.println("myself db  连接池不存在，无法关闭 !");
			return;
		}

		PooledConnection_Self pConn = null;
		Enumeration<PooledConnection_Self> enumerate = this.connections.elements();
		while(enumerate.hasMoreElements())
		{
			pConn = (PooledConnection_Self)enumerate.nextElement();

			if(pConn.isBusy())
			{
				wait(5000);
			}

			closeConnection(pConn.getConnection());
			this.connections.removeElement(pConn);
			System.out.println("删除mySelf连接,当前总连接数:" + this.connections.size());
		}

		this.connections = null;
	}

	private void closeConnection(Connection conn)
	{
		try
		{
			System.out.println("the self 关闭数据库进行时" + Com_Fun.DateTimeStr("yyyy-MM-dd HH:mm:ss"));
			conn.close();
		}
		catch(SQLException e)
		{
			System.out.println("myself db  关闭数据库连接出错： " + e.getMessage());
		}
	}

	private void wait(int mSeconds)
	{
		try
		{
			Thread.sleep(mSeconds);
		}
		catch(InterruptedException localInterruptedException)
		{
		}
	}
}